﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Text;
using System.IO;
using System.Windows.Forms;
using Microsoft.Win32;
using System.Text.RegularExpressions;
using System.Drawing.Drawing2D;
[assembly: CLSCompliant(false)]

namespace DeskNote
{
   
    public class ControlContainer : IContainer
    {
        ComponentCollection _components;
        public ControlContainer()
        {
            _components = new ComponentCollection(new IComponent[] { });
        }
        public ComponentCollection Components
        {
            get
            {
                return _components;
            }
        }
        public void Dispose()
        {
            GC.SuppressFinalize(this);
            _components = null;
        }
        #region IContainer Members
        public void Add(IComponent component, string name) { } public void Add(IComponent component) { } public void Remove(IComponent component) { }
        #endregion
    }

    internal sealed class Program : IDisposable
    {
        const string comment = @"#This is a comment
#File should contain the below line to set the position, color, size of the text
#[x-coord,y-coord,color,size]
#
[500,500,Red,15]
1. Reminder Note";
        string message = string.Empty;
        string OriginalWall = "";
        string DuplicateWall = "";
        bool wallChanged = false;
        bool firstRun = true;
        int errCount = 0;
        private NotifyIcon notifyIcon1;
        ControlContainer container;
        /// <summary>
        /// Main entry method, uses mutex to run only one instance of application
        /// </summary>
        [STAThread]
        static void Main()
        {
            bool createdNew = true;
            using (System.Threading.Mutex mutex = new System.Threading.Mutex(true, "DeskNote", out createdNew))
            {
                if (createdNew)
                {
                    new Program().Init();
                }
            }
        }
        /// <summary>
        /// Starting point,inits Hooks, notification Icon and event handlers
        /// </summary>
        private void Init()
        {
            InterceptKeys.EnableHook();
            InitNotificationIcon();
            Start();
            Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
            Application.ThreadExit += new EventHandler(Application_ApplicationExit);
            Application.Run();
        }
        /// <summary>
        /// On application exit, close hook and revert wallpaper to original
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Application_ApplicationExit(object sender, EventArgs e)
        {
            InterceptKeys.ReleaseHook();
            if (container != null)
                container.Dispose();
            SetWallPaper(OriginalWall);
        }
        /// <summary>
        /// Create notification Icon and attach events
        /// </summary>
        private void InitNotificationIcon()
        {
            container = new ControlContainer();
            notifyIcon1 = new NotifyIcon(container);
            MenuItem Quit = new MenuItem("Quit");
            MenuItem ChangePos = new MenuItem("Change Note Location");
            ContextMenu myMenu = new ContextMenu();
            
            Quit.Click += (sender, e) =>
            { // SetWallPaper(OriginalWall);
                notifyIcon1.Icon = null;
                notifyIcon1.Visible = true;
                notifyIcon1.Visible = false;
                Application.Exit();
            };
            ChangePos.Click += (sender, e) =>
                {
                    ShowMessage("Click anywhere on the desktop to set the location of the text.");
                    InitChangePos();
                };
            myMenu.MenuItems.Add(ChangePos);
            myMenu.MenuItems.Add(Quit);
            notifyIcon1.Visible = true;
            notifyIcon1.Icon = new Icon("Dnotes.ico");
            // TextToIcon("CT");
            notifyIcon1.Text = "DeskNote";
            notifyIcon1.ContextMenu = myMenu;
            notifyIcon1.BalloonTipTitle = "DeskNote";
            notifyIcon1.Click += (sender, e) =>
                {
                    if ((e as MouseEventArgs).Button == MouseButtons.Left)
                    {
                        ShowMessage("Current todo file:" + Environment.NewLine + Settings.ToDoPath);
                    }
                };

            notifyIcon1.BalloonTipClicked += (sender, e) =>
                {
                    Process.Start(Settings.ToDoPath);
                };
        }
        /// <summary>
        /// Show cutom message in Notification Balloon
        /// </summary>
        /// <param name="message"></param>
        private void ShowMessage(string message)
        {
            notifyIcon1.BalloonTipText = message;
            notifyIcon1.ShowBalloonTip(2000);
        }
        /// <summary>
        /// Attaches filesystem watcher to the todo file
        /// </summary>
        private void Start()
        {
            GetMessage();
            firstRun = false;
            FileSystemWatcher notesWatcher = new FileSystemWatcher();
            notesWatcher.Changed += new FileSystemEventHandler(notesWatcher_Changed);
            notesWatcher.Path = Path.GetDirectoryName(Settings.ToDoPath);
            notesWatcher.Filter = Path.GetFileName(Settings.ToDoPath);
            notesWatcher.EnableRaisingEvents = true;
            notesWatcher_Changed(null, null);
        }
        /// <summary>
        /// Verifies the Wallpaper, updates location in case wallpaper has changed and create a duplicate wallpaper to use
        /// </summary>
        private void CheckWall()
        {
            if (string.IsNullOrEmpty(Settings.OriginalWall) ||
                Path.GetFileNameWithoutExtension(GetWallPaperPath()).IndexOf(Path.GetFileNameWithoutExtension(Settings.OriginalWall)) > 1 ||
                Path.GetFileNameWithoutExtension(GetWallPaperPath()).IndexOf(Path.GetFileNameWithoutExtension(Settings.OriginalWall)) == -1)
            {
                Settings.OriginalWall = GetWallPaperPath();
                wallChanged = true;
            }
            if (wallChanged || firstRun)
            {
                wallChanged = false;
                OriginalWall = Settings.OriginalWall;
                DuplicateWall = Path.Combine(Path.GetDirectoryName(OriginalWall), Path.GetFileNameWithoutExtension(OriginalWall) + "Copy");

                if (!File.Exists(DuplicateWall))
                    File.Copy(OriginalWall, DuplicateWall);
            }
        }

        /// <summary>
        /// Get the todo file text
        /// </summary>
        void GetMessage()
        {
            CheckWall();
            System.Threading.Thread.Sleep(1000);
            if (File.Exists(Settings.ToDoPath))
            {
                message = FileIO.Message;
            }
            else
            {
                using (OpenFileDialog ofd = new OpenFileDialog())
                {
                    ofd.InitialDirectory = "C:\\";
                    ofd.Filter = "txt files (*.txt)|*.txt|All files(*.*)|*.*";
                    ofd.FilterIndex = 1;
                    ofd.RestoreDirectory = true;
                    ofd.Title = "Select a ToDo file";
                    ofd.CheckFileExists = true;
                    if (ofd.ShowDialog() == DialogResult.OK)
                    {
                        Settings.ToDoPath = ofd.FileName;
                        string oldData = string.Empty;
                        oldData = FileIO.Message;
                        if (oldData.IndexOf("#[x-coord,y-coord,color,size]") == -1)
                        {
                            FileIO.Message = comment;
                            if (!string.IsNullOrEmpty(oldData))
                                FileIO.Message = oldData;
                        }
                    }
                    else
                    {
                        message = "TODO FILE MISSING";
                        WriteToWall(message);
                        System.Threading.Thread.CurrentThread.Abort();
                    }
                }
            }
        }

        /// <summary>
        /// Event handler for change in Todo file
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void notesWatcher_Changed(object sender, FileSystemEventArgs e)
        {
            GetMessage();
            WriteToWall(message);
        }

        /// <summary>
        /// Write the message on wallpaper
        /// </summary>
        /// <param name="message"></param>
        void WriteToWall(string message)
        {
            int screenX = Screen.PrimaryScreen.Bounds.Width/2;
            int screenY = Screen.PrimaryScreen.Bounds.Height/2;
            string tempWall = Path.Combine(Path.GetDirectoryName(GetWallPaperPath()), "Notes_Wall");
            File.Copy(OriginalWall, DuplicateWall, true);
            using (Bitmap wallpaperImage = new Bitmap(DuplicateWall))
            {
                using (Graphics g = Graphics.FromImage(wallpaperImage))
                {
                    int gX = wallpaperImage.Width/2;
                    int gY = wallpaperImage.Height/2;
                    
                    g.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit | TextRenderingHint.ClearTypeGridFit;
                    Customize cm = new Customize(message);
                    float fontSize = (72 / wallpaperImage.HorizontalResolution) * cm.FontSize;
                    g.DrawString(cm.Message, new Font("Tahoma", fontSize, FontStyle.Regular), cm.FontColor, new Rectangle(cm.X_Coord + (gX - screenX), cm.Y_Coord + (gY- screenY), Screen.PrimaryScreen.Bounds.Width / 4, Screen.PrimaryScreen.Bounds.Height));
                    g.Save();
                } wallpaperImage.Save(tempWall);
            }

            while (!CopyFiles(tempWall, DuplicateWall) && errCount < 5) ;
            SetWallPaper(DuplicateWall);
        }

        /// <summary>
        /// Copies file, used in case there is an error in copying. Retries 5 times and throws error 
        /// </summary>
        /// <param name="temp"></param>
        /// <param name="dup"></param>
        /// <returns></returns>
        private bool CopyFiles(string temp, string dup)
        {
            System.Threading.Thread.Sleep(1500);
            try
            {
                File.Copy(temp, dup, true);
                errCount = 0;
                return true;
            }
            catch (Exception ex)
            {
                errCount++;
                if (errCount < 5)
                    return false;
                else
                {
                    MessageBox.Show(ex.Message,"DeskNote", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return false;
                }
            }
        }
        /// <summary>
        /// Find wallpaper path from registry
        /// </summary>
        /// <returns></returns>
        private static string GetWallPaperPath()
        {
            RegistryKey wallPaper = Registry.CurrentUser.OpenSubKey("Control Panel\\Desktop", false);
            string Path = wallPaper.GetValue("WallPaper").ToString();
            wallPaper.Close();
            return Path;
        }
        /// <summary>
        /// Sets wallpaper path and updates screen
        /// </summary>
        /// <param name="path"></param>
        private static void SetWallPaper(string path)
        {
            NativeMethods.SystemParametersInfo(20, 0, path, 0x01 | 0x02);
        }
        /// <summary>
        /// Starts process of changing the location of text on screen
        /// </summary>
        private void InitChangePos()
        {
            InterceptMouse.HookMouse();
            InterceptMouse.MouseClicked += new InterceptMouse.MouseClickHandler(InterceptMouse_MouseClicked);
        }
        /// <summary>
        /// Event handler for mouse click, used to get location of the new position, sets location in todo file
        /// </summary>
        void InterceptMouse_MouseClicked()
        {
            InterceptMouse.MouseClicked -= new InterceptMouse.MouseClickHandler(InterceptMouse_MouseClicked);
            InterceptMouse.UnHookMouse();
            Regex formatPattern = new Regex(@"\[([0-9]*),([0-9]*),(\w*),([0-9]*)\]", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.ECMAScript);
            string _message = FileIO.Message;
            string oldPos = string.Empty;
            string newPos = string.Empty;
            if (formatPattern.IsMatch(_message))
            {
                if (formatPattern.Matches(_message).Count == 1)
                {
                    Match mt = formatPattern.Match(_message);
                    GroupCollection gc = mt.Groups;
                    newPos = "["+InterceptMouse.MousePos.X.ToString()+","+InterceptMouse.MousePos.Y.ToString();
                    oldPos = "[" + gc[1].Value.ToString() + "," + gc[2].Value.ToString();
                    _message = _message.Replace(oldPos, newPos);
                    FileIO.Message = _message;
                }
            }
            FileIO.Message = _message;
        }

        #region IDisposable Members

        public void Dispose()
        {
            notifyIcon1.Dispose();
            container.Dispose();
        }

        #endregion
    }
}
